package org.acghub.common;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 单线程写 多线程读 版本快照环形缓冲
 *
 * @Project demos
 * @Package org.acghub.common
 * @Desc
 * @Author Administrator
 * @Date 2025/7/17/星期四 17:52
 * @Version 1.0
 */
public class SPMCRingBuffer<E> {

    private static final int DEFAULT_MAX_SIZE = 1024;

    private final AtomicLong version = new AtomicLong(0);

    private final Object[] buffer;

    private final int capacity;

    private volatile int writeIndex = 0;

    private volatile int size = 0;

    public SPMCRingBuffer(int capacity) {
        this.capacity = capacity;
        this.buffer = new Object[capacity];
    }

    public SPMCRingBuffer() {
        this(DEFAULT_MAX_SIZE);
    }

    // 单线程追加
    public void append(E value) {
        // 写入新消息
        buffer[writeIndex] = value;

        // 更新指针
        int nextIndex = (writeIndex + 1) % capacity;
        if (size < capacity) {
            size++;
        } else {
            // 已满时覆盖最旧消息（位置就是当前writeIndex）
            nextIndex = (writeIndex + 1) % capacity;
        }
        writeIndex = nextIndex;

        // 更新版本号（写屏障保证可见性）
        version.incrementAndGet();
    }

    E value(int i) {
        return (E) buffer[i];
    }

    public E get(int index) {
        if (index < 0 || index >= capacity) {
            throw new IndexOutOfBoundsException("index: " + index);
        }
        // 获取版本号（读屏障保证可见性）
        long startVersion;
        E value;
        do {
            startVersion = version.get();
            if (index >= size) {
                return null;
            }
            value = value(index);
        } while (startVersion != this.version.get());
        return value;
    }

    // 多线程安全读取快照
    public List<E> getSnapshot() {
        long startVersion;
        List<E> snapshot;
        do {
            // 获取当前状态（volatile读）
            startVersion = version.get();
            final int currentSize = size;
            final int currentWriteIndex = writeIndex;

            // 创建快照数组
            snapshot = new ArrayList<>();

            if (currentSize < capacity) {
                // 未满：直接复制0~count-1
                for (int i = 0; i < currentSize; i++) {
                    snapshot.add(value(i));
                }
            } else {
                // 已满：环形复制
                for (int i = 0; i < currentSize; i++) {
                    int index = (currentWriteIndex + i) % capacity;
                    snapshot.add(value(index));
                }
            }
        } while (version.get() != startVersion); // 检查版本变化

        return snapshot;
    }

    public boolean isFull() {
        long startVersion;
        boolean full;
        do {
            startVersion = version.get();
            final int currentSize = size;
            full = currentSize >= capacity;
        } while (version.get() != startVersion);
        return full;
    }
}
